<template>
  <div class="log-analyzer">
    <!-- 全局遮罩层 -->
    <div v-if="isUploading" class="upload-overlay">
      <div class="upload-loading">
        <i class="el-icon-loading"></i>
        <p>正在上传并分析日志文件，请稍候...</p>
        <el-progress 
          :percentage="uploadProgress" 
          :stroke-width="8"
          :show-text="false"
          class="upload-progress-bar"
        ></el-progress>
        <p class="upload-status">{{ uploadStatus }}</p>
      </div>
    </div>

    <el-card class="box-card">
      <div slot="header" class="clearfix">
        <span>日志解析</span>
      </div>
      <el-form :inline="true" label-width="100px">
        <el-form-item label="选择模板">
          <el-select v-model="selectedTemplateId" placeholder="请选择日志模板">
            <el-option
              v-for="item in templates"
              :key="item.id"
              :label="item.name"
              :value="item.id"
            />
          </el-select>
        </el-form-item>
        <el-form-item label="上传日志">
          <el-upload
            class="upload-area"
            :http-request="handleFileUpload"
            :show-file-list="false"
            accept=".log,.txt"
            action=""
            :disabled="isUploading"
          >
            <el-button type="primary" :loading="isUploading">选择文件</el-button>
          </el-upload>
        </el-form-item>
      </el-form>
      <el-progress
        v-if="uploadProgress > 0 && uploadProgress < 100 && !isUploading"
        :percentage="uploadProgress"
        :stroke-width="6"
        class="upload-progress"
      ></el-progress>
      <el-alert
        v-if="errorMsg"
        :title="errorMsg"
        type="error"
        show-icon
        style="margin: 10px 0"
      />
    </el-card>

    <el-card class="box-card">
      <div slot="header" class="clearfix">
        <span>慢SQL分析结果 (共 {{ totalResults.length }} 条)</span>
        <div style="float: right">
          <el-button size="mini" @click="exportToCSV" type="success"
            >导出CSV</el-button
          >
          <el-button size="mini" @click="clearResults" type="danger"
            >清空结果</el-button
          >
        </div>
      </div>

      <!-- 搜索和过滤 -->
      <div class="search-bar" style="margin-bottom: 15px">
        <el-input
          v-model="searchKeyword"
          placeholder="搜索SQL、Mapper或参数..."
          style="width: 300px; margin-right: 10px"
          clearable
          @input="handleSearch"
        >
          <i slot="prefix" class="el-input__icon el-icon-search"></i>
        </el-input>
        <el-select
          v-model="filterDuration"
          placeholder="执行时间过滤"
          style="width: 150px; margin-right: 10px"
          clearable
        >
          <el-option label="> 1秒" value="1000"></el-option>
          <el-option label="> 5秒" value="5000"></el-option>
          <el-option label="> 10秒" value="10000"></el-option>
          <el-option label="> 30秒" value="30000"></el-option>
        </el-select>
        <el-tooltip
          content="过滤执行时间超过指定阈值的SQL，时间单位为毫秒"
          placement="top"
        >
          <i
            class="el-icon-question"
            style="color: #909399; margin-left: 5px; cursor: help"
          ></i>
        </el-tooltip>
        <el-button @click="handleSearch" type="primary" size="small"
          >搜索</el-button
        >
        <el-button @click="resetSearch" size="small">重置</el-button>
        <el-button @click="performSearch" type="info" size="small"
          >应用过滤</el-button
        >
      </div>

      <!-- 虚拟滚动表格 -->
      <div class="virtual-table-container" ref="tableContainer">
        <!-- 表头 -->
        <div class="virtual-table-header">
          <div class="header-cell" style="width: 80px">行号</div>
          <div class="header-cell" style="width: 200px">Mapper</div>
          <div
            class="header-cell sql-header-cell"
            style="flex: 2; min-width: 400px"
          >
            SQL语句
          </div>
          <div class="header-cell" style="width: 220px">参数</div>
          <div class="header-cell" style="width: 120px">执行时间</div>
          <div class="header-cell" style="width: 180px">开始时间</div>
        </div>

        <div class="virtual-table-body" ref="tableBody" @scroll="handleScroll">
          <div
            class="virtual-table-content"
            :style="{ height: totalHeight + 'px' }"
          >
            <!-- 表体 -->
            <div
              v-for="(item, index) in visibleItems"
              :key="item.lineNumber + '_' + index"
              class="virtual-table-row"
              :style="{ transform: `translateY(${item.offset}px)` }"
            >
              <div class="cell" style="width: 80px">{{ item.lineNumber }}</div>
              <div class="cell" style="width: 200px" :title="item.mapperName">
                {{ item.mapperName }}
              </div>
              <div
                class="cell sql-cell"
                style="flex: 2; min-width: 400px"
                :title="item.sql"
              >
                {{ item.sql }}
              </div>
              <div class="cell" style="width: 220px" :title="item.parameters">
                {{ item.parameters }}
              </div>
              <div class="cell" style="width: 120px">
                {{ item.durationFormatted }}
              </div>
              <div class="cell" style="width: 180px">{{ item.startTime }}</div>
            </div>
          </div>
        </div>
      </div>

      <!-- 分页信息 -->
      <div
        class="pagination-info"
        style="margin-top: 10px; text-align: center; color: #666"
      >
        <div
          v-if="filteredResults.length === 0 && totalResults.length > 0"
          style="color: #e6a23c; margin-bottom: 10px"
        >
          <i class="el-icon-warning"></i>
          当前过滤条件下没有找到匹配的结果，请尝试调整搜索条件或重置过滤
        </div>
        显示第 {{ startIndex + 1 }} - {{ endIndex }} 条，共
        {{ filteredResults.length }} 条结果
        <span
          v-if="filteredResults.length !== totalResults.length"
          style="color: #909399"
        >
          (原始数据 {{ totalResults.length }} 条)
        </span>
      </div>
    </el-card>
  </div>
</template>

<script>
import axios from "axios";

export default {
  name: "LogAnalyzer",
  data() {
    return {
      templates: [],
      selectedTemplateId: "",
      uploadProgress: 0,
      totalResults: [], // 所有结果
      filteredResults: [], // 过滤后的结果
      visibleItems: [], // 当前可见的项目
      errorMsg: "",
      apiBaseUrl: "http://localhost:8080/api/template",
      templateApi: "http://localhost:8080/api/template",

      // 虚拟滚动相关
      itemHeight: 50, // 每行高度
      visibleCount: 20, // 可见行数
      startIndex: 0,
      endIndex: 0,
      scrollTop: 0,

      // 搜索和过滤
      searchKeyword: "",
      filterDuration: "",

      // 防抖
      searchTimeout: null,

      // 上传状态
      isUploading: false,
      uploadStatus: "准备中...",
    };
  },
  computed: {
    totalHeight() {
      return this.filteredResults.length * this.itemHeight;
    },
  },
  created() {
    this.loadTemplates();
  },
  mounted() {
    this.initVirtualScroll();
  },
  watch: {
    // 监听过滤条件变化，自动触发搜索
    filterDuration() {
      this.handleSearch();
    },
    searchKeyword() {
      this.handleSearch();
    },
  },
  methods: {
    async loadTemplates() {
      try {
        const res = await axios.get(this.templateApi);
        this.templates = res.data;
      } catch (e) {
        this.$message.error("获取模板失败");
      }
    },

    async handleFileUpload(options) {
      if (!this.selectedTemplateId) {
        this.$message.error("请先选择日志模板");
        return;
      }
      const formData = new FormData();
      formData.append("file", options.file);
      formData.append("templateId", this.selectedTemplateId);
      this.uploadProgress = 10;
      this.errorMsg = "";
      this.totalResults = [];
      this.filteredResults = [];
      this.visibleItems = [];
      this.isUploading = true;
      this.uploadStatus = "正在上传文件...";
      
      try {
        this.uploadProgress = 30;
        this.uploadStatus = "正在分析日志文件...";
        const response = await axios.post(
          `${this.apiBaseUrl}/upload`,
          formData,
          {
            headers: { "Content-Type": "multipart/form-data" },
            onUploadProgress: (progressEvent) => {
              this.uploadProgress =
                30 +
                Math.round((progressEvent.loaded * 70) / progressEvent.total);
              this.uploadStatus = `上传进度: ${Math.round(this.uploadProgress)}%`;
            },
          }
        );
        this.uploadProgress = 100;
        this.uploadStatus = "分析完成，正在处理结果...";
        
        if (response.data.success) {
          this.totalResults = response.data.data || [];
          this.filteredResults = [...this.totalResults];
          this.updateVisibleItems();
          this.uploadStatus = "处理完成";
          this.$message.success(
            `分析完成！共发现 ${this.totalResults.length} 条慢SQL`
          );
        } else {
          this.errorMsg = response.data.message || "分析失败";
          this.uploadStatus = "分析失败";
        }
      } catch (error) {
        this.uploadProgress = 0;
        this.errorMsg =
          (error.response &&
            error.response.data &&
            error.response.data.message) ||
          error.message;
        this.uploadStatus = "上传失败";
        this.$message.error("文件上传或分析失败: " + this.errorMsg);
      } finally {
        this.isUploading = false;
      }
    },

    // 虚拟滚动相关方法
    initVirtualScroll() {
      this.updateVisibleItems();
    },

    handleScroll(e) {
      this.scrollTop = e.target.scrollTop;
      this.updateVisibleItems();
    },

    updateVisibleItems() {
      const start = Math.floor(this.scrollTop / this.itemHeight);
      const end = Math.min(
        start + this.visibleCount,
        this.filteredResults.length
      );

      this.startIndex = start;
      this.endIndex = end;

      this.visibleItems = this.filteredResults
        .slice(start, end)
        .map((item, index) => ({
          ...item,
          offset: (start + index) * this.itemHeight,
        }));
    },

    // 搜索和过滤
    handleSearch() {
      if (this.searchTimeout) {
        clearTimeout(this.searchTimeout);
      }

      this.searchTimeout = setTimeout(() => {
        this.performSearch();
      }, 300);
    },

    performSearch() {
      let results = [...this.totalResults];

      // 关键词搜索
      if (this.searchKeyword) {
        const keyword = this.searchKeyword.toLowerCase();
        results = results.filter(
          (item) =>
            (item.sql && item.sql.toLowerCase().includes(keyword)) ||
            (item.mapperName &&
              item.mapperName.toLowerCase().includes(keyword)) ||
            (item.parameters && item.parameters.toLowerCase().includes(keyword))
        );
      }

      // 执行时间过滤
      if (this.filterDuration) {
        const threshold = parseInt(this.filterDuration);
        results = results.filter((item) => {
          // 使用 durationMillis 字段，如果不存在则使用 duration
          const duration = parseInt(item.durationMillis || item.duration) || 0;
          return duration > threshold;
        });
      }

      this.filteredResults = results;
      this.scrollTop = 0;
      this.updateVisibleItems();
    },

    resetSearch() {
      this.searchKeyword = "";
      this.filterDuration = "";
      this.filteredResults = [...this.totalResults];
      this.scrollTop = 0;
      this.updateVisibleItems();
    },

    // 导出功能
    exportToCSV() {
      if (this.filteredResults.length === 0) {
        this.$message.warning("没有数据可导出");
        return;
      }

      const headers = [
        "行号",
        "Mapper",
        "SQL语句",
        "参数",
        "执行时间",
        "开始时间",
      ];
      const csvContent = [
        headers.join(","),
        ...this.filteredResults.map((item) =>
          [
            item.lineNumber,
            `"${item.mapperName || ""}"`,
            `"${item.sql || ""}"`,
            `"${item.parameters || ""}"`,
            item.durationFormatted,
            item.startTime,
          ].join(",")
        ),
      ].join("\n");

      const blob = new Blob(["\ufeff" + csvContent], {
        type: "text/csv;charset=utf-8;",
      });
      const link = document.createElement("a");
      const url = URL.createObjectURL(blob);
      link.setAttribute("href", url);
      link.setAttribute(
        "download",
        `慢SQL分析结果_${new Date()
          .toISOString()
          .slice(0, 19)
          .replace(/:/g, "-")}.csv`
      );
      link.style.visibility = "hidden";
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
    },

    clearResults() {
      this.$confirm("确定要清空所有分析结果吗？", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      }).then(() => {
        this.totalResults = [];
        this.filteredResults = [];
        this.visibleItems = [];
        this.searchKeyword = "";
        this.filterDuration = "";
        this.$message.success("结果已清空");
      });
    },
  },
};
</script>

<style scoped>
.log-analyzer {
  width: 100%;
  margin: 1% auto;
}
.box-card {
  margin-bottom: 20px;
}
.upload-progress {
  margin-top: 10px;
}

/* 虚拟滚动表格样式 */
.virtual-table-container {
  border: 1px solid #ebeef5;
  border-radius: 4px;
  overflow: hidden;
}

.virtual-table-header {
  display: flex;
  background-color: #f5f7fa;
  border-bottom: 1px solid #ebeef5;
  font-weight: bold;
  color: #606266;
}

.header-cell {
  padding: 12px 8px;
  border-right: 1px solid #ebeef5;
  text-align: center;
  font-size: 14px;
}

.header-cell:last-child {
  border-right: none;
}

.virtual-table-body {
  height: 600px;
  overflow-y: auto;
  position: relative;
}

.virtual-table-content {
  position: relative;
}

.virtual-table-row {
  display: flex;
  position: absolute;
  width: 100%;
  border-bottom: 1px solid #f0f0f0;
  background-color: #fff;
  transition: background-color 0.2s;
}

.virtual-table-row:hover {
  background-color: #f5f7fa;
}

.virtual-table-row:nth-child(even) {
  background-color: #fafafa;
}

.virtual-table-row:nth-child(even):hover {
  background-color: #f5f7fa;
}

.cell {
  padding: 12px 8px;
  border-right: 1px solid #f0f0f0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 14px;
  color: #606266;
}

.cell:last-child {
  border-right: none;
}

.sql-cell {
  flex: 2;
  min-width: 400px;
  max-width: 1000px;
  overflow: auto;
  white-space: pre-line;
  word-break: break-all;
}

.sql-header-cell {
  flex: 2;
  min-width: 400px;
  max-width: 1000px;
  overflow: auto;
  white-space: pre-line;
  word-break: break-all;
}

.search-bar {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
}

.pagination-info {
  font-size: 12px;
}

/* 上传遮罩层样式 */
.upload-overlay {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.7);
  display: flex;
  justify-content: center;
  align-items: center;
  z-index: 1000;
  backdrop-filter: blur(5px);
}

.upload-loading {
  background-color: #fff;
  padding: 30px;
  border-radius: 8px;
  text-align: center;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  width: 400px;
  max-width: 90%;
}

.upload-loading i {
  font-size: 40px;
  color: #409eff;
  margin-bottom: 15px;
}

.upload-loading p {
  font-size: 16px;
  color: #303133;
  margin-bottom: 15px;
}

.upload-progress-bar {
  margin-bottom: 15px;
  width: 80%;
}

.upload-status {
  font-size: 14px;
  color: #606266;
}
</style> 